﻿#include "stdafx.h"
#include "script.h"
#include "thread_control.h"
#include "log.h"
#include "resource.h"
#include "GameAppDlg.h"
#include "ScriptMapleZk.h"
#include "ScriptMapleWls.h"
#include "ScriptMaple.h"
//#include "GameAppDlg.h"
//

unsigned WINAPI SubThread(PVOID pParam);
void CheckException(long index);
//
// 我们做暂停和恢复操作,就主要靠这个延时函数,要求脚本所有用到延时的地方，全部用这个，这样我们可以有很多机会去暂停线程
void ScriptDelay(long index, long time)
{
	// 判断是否有暂停和结束标记
	if (g_info[index].is_stop)
	{
		// 直接退出当前线程,退出前一定要在本线程内解绑,因为绑定模式0和2在线程外解绑的话会失败,导致解绑失败.
		if (g_info[index].dm)
		{
			g_info[index].dm->UnBindWindow();
		}
		_endthreadex(0);
	}

	if (g_info[index].is_pause)
	{
		g_info[index].thread_state = State_Pause;
		ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

		// 如果你想要在暂停时让用户可以操作,那么可以调用EnableBind,但是不要去调用LockInput,LockInput不是用来解除后台的,具体参考LockInput的说明
		if (g_info[index].dm)
		{
			g_info[index].dm->EnableBind(5);
		}

		// 我们暂停的方法是死循环,然后延时,而不是调用系统的接口
		// 这样开销最小,并且效率也还不错
		while (1)
		{
			if (!g_info[index].is_pause)
			{
				g_info[index].thread_state = State_Runing;
				ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

				// 开启后台
				if (g_info[index].dm)
				{
					g_info[index].dm->EnableBind(1);
				}
				break;
			}

			if (g_info[index].is_stop)
			{
				// 直接退出当前线程,退出前一定要在本线程内解绑,因为绑定模式0和2在线程外解绑的话会失败,导致解绑失败.
				if (g_info[index].dm)
				{
					g_info[index].dm->UnBindWindow();
				}
				_endthreadex(0);
			}

			Sleep(1);
		}
	}

	// 可能暂停,恢复时会让状态错乱,这里再判断一次
	if (g_info[index].thread_state != State_Runing)
	{
		g_info[index].thread_state = State_Runing;
		ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

		// 开启后台
		if (g_info[index].dm)
		{
			g_info[index].dm->EnableBind(1);
		}
	}

	Sleep(time);
}

//选中指定线路
bool ChangeLine(CString strLine) {
	//查找迅游窗口是否存在 不存在则启动迅游
	long x, y, x1, y1;
	long hwnd = g_dm->FindWindowW(L"XunYouMainClass_4B32", L"迅游国际版");
	if (hwnd == 0) {
		g_dm->RunApp(L"D:\\Program Files (x86)\\XunYou_Intl\\xunyou.exe", 0);
		Sleep(5000);
		for (size_t i = 0; i < 15; i++)
		{
			g_dm->FindPic(0, 0, 1280, 960, L"xytag.bmp", L"050505", 0.95, 0, &x, &y);
			if (x > 0) {
				hwnd = g_dm->FindWindowW(L"XunYouMainClass_4B32", L"迅游国际版");
				break;
			}
			Sleep(1000);
		}
	}
	g_dm->SetWindowState(hwnd, 12);
	g_dm->UnBindWindow();
	int ret = g_dm->BindWindowEx(hwnd, L"normal", L"normal", L"normal", L"normal", 0);
	g_dm->SetDict(2, L"line.txt");
	g_dm->UseDict(2);
	if (ret > 0) {
		for (size_t i = 0; i < 5; i++)
		{
			//g_dm->BindWindowEx(hwnd, L"normal", L"normal", L"normal", L"normal", 0);
			//识别迅游窗口内线路是否是需要连接的线路
			g_dm->FindPic(0, 0, 1280, 960, L"startnet.bmp|nostartnet.bmp", L"050505", 0.95, 0, &x, &y);
			CString str;
			if (x > 0) {
				str = g_dm->Ocr(x - 100, y, x + 240, y + 230, L"bbbbbb-666666", 1);
			}

			//CString str = g_dm->Ocr(x3 - 188, y3 + 10, x3, y3 + 200, L"bbbbbb-555555", 1);
			//g_main_cwnd->AppendText(L"识别数据:" + str);

			if (str == strLine) {//如果迅游窗口内的线路为需要的线路则直接启动线路
				g_dm->FindPic(0, 0, 1280, 960, L"startnet.bmp", L"050505", 0.95, 0, &x, &y);
				if (x > 0) {//启动成功后返回
					return true;
				}
				g_dm->FindPic(0, 0, 1280, 960, L"nostartnet.bmp", L"050505", 0.95, 0, &x, &y);
				if (x > 0) {//找到线路后启动线路
					g_dm->MoveTo(x, y);
					g_dm->LeftClick();
					Sleep(15000);
					return true;
				}
			}
			else {
				Sleep(1000);
				g_dm->UnBindWindow();
				g_dm->SetDict(2, L"line.txt");
				g_dm->UseDict(2);
				//查找所需的线路并点击选中线路
				g_dm->FindPic(0, 0, 1280, 960, L"startnet.bmp", L"050505", 0.95, 0, &x1, &y1);
				if (x1 > 0) {//未识别到线路已经启动线路则先关闭线路
					g_main_cwnd->AppendText(L"网络已连接关闭网络");
					g_dm->MoveTo(x1 + 33, y1 - 32);
					g_dm->LeftClick();
					Sleep(5000);
				}
				g_dm->FindPic(0, 0, 1280, 960, L"nostartnet.bmp", L"050505", 0.95, 0, &x1, &y1);
				if (x1 > 0) {
					g_dm->FindPic(0, 0, 1280, 960, L"netlist.bmp", L"050505", 0.9, 0, &x, &y);
					if (x == -1) {
						g_main_cwnd->AppendText(L"网络未连接");
						g_dm->MoveTo(x1 + 67, y1 + 85);
						g_dm->LeftClick();
						Sleep(2000);
					}
				}
				//查找线路列表是否开启
				g_dm->FindPic(0, 0, 1280, 960, L"netlist.bmp", L"050505", 0.9, 0, &x, &y);
				if (x > 0) {
					g_dm->MoveTo(x - 148, y + 39);
					g_dm->LeftClick();
					Sleep(3000);
					g_dm->MoveTo(x, y + 88);
					g_dm->LeftClick();
					Sleep(2000);
					long x3 = x, y3 = y;
					for (size_t i = 0; i < 200; i++)
					{
						str = g_dm->Ocr(x3 - 188, y3 + 10, x3, y3 + 200, L"bbbbbb-555555", 1);
						//CString str = g_dm->Ocr(x3 - 188, y3 + 10, x3, y3 + 200, L"bbbbbb-555555", 1);
						g_main_cwnd->AppendText(strLine + L"识别数据2:" + str);
						g_dm->FindStrFast(x3 - 188, y3 + 10, x3, y3 + 200, strLine, L"bbbbbb-555555", 1, &x, &y);
						if (x > 0) {//找到线路并点击
							g_dm->MoveTo(x, y);
							g_dm->LeftClick();
							Sleep(2000);
							g_dm->FindPic(0, 0, 1280, 960, L"nostartnet.bmp", L"050505", 0.95, 0, &x1, &y1);
							if (x1 > 0) {
								g_dm->MoveTo(x1, y1);
								g_dm->LeftClick();
								Sleep(15000);
								g_dm->BindWindowEx(hwnd, L"normal", L"normal", L"normal", L"normal", 0);
								//识别迅游窗口内线路是否是需要连接的线路
								str = g_dm->Ocr(52, 444, 207, 490, L"bbbbbb-555555", 1);
								//CString str = g_dm->Ocr(x3 - 188, y3 + 10, x3, y3 + 200, L"bbbbbb-555555", 1);
								/*g_main_cwnd->AppendText(L"识别数据1:" + str);
								if (str == strLine)
								{*/
								g_dm->SetWindowState(hwnd, 2);
								return true;
								//}
							}
							break;
						}
						g_dm->WheelDown();
						Sleep(500);
					}//未找到关闭线路列表重新打开
					g_dm->FindPic(0, 0, 1280, 960, L"startnet.bmp", L"050505", 0.95, 0, &x1, &y1);
					if (x1 > 0) {//未识别到线路已经启动线路则先关闭线路
						g_dm->MoveTo(x1 + 33, y1 - 32);
						g_dm->LeftClick();
						Sleep(5000);
					}
					g_dm->FindPic(0, 0, 1280, 960, L"nostartnet.bmp", L"050505", 0.95, 0, &x, &y);
					g_dm->MoveTo(x + 67, y + 85);
					g_dm->LeftClick();
				}
				else {
					g_dm->FindPic(0, 0, 1280, 960, L"nostartnet.bmp", L"050505", 0.95, 0, &x, &y);
					if (x > 0) {
						g_dm->MoveTo(x + 67, y + 85);
						g_dm->LeftClick();
						Sleep(1000);
					}
				}
			}
		}
	}
	return false;
}

//切换线路
void SwitchingLines(int nCfgLine, int nListLine)
{
	if (nCfgLine == -1) {//首次启动迅游
		g_main_cwnd->AppendText(L"首次启动线路:" + arrLineCode[1]);
		if (ChangeLine(arrLineCode[1])) {
			g_main_cwnd->AppendText(L"加速成功");
			g_IniFile.SetInt(L"Set", L"CodeLine", 1);
			g_main_cwnd->SetDlgItemTextW(IDC_EDIT3, L"1");
			//g_main_cwnd->GetDlgItem(IDC_STATIC5);
		}
		//取下标为0的线路
		//g_main_cwnd->
		//CListBox* list = (CListBox*)g_main_cwnd->GetDlgItem(IDC_LIST1);

		//启动成功后更新配置线路
	}
	else if (nCfgLine != -1 && nCfgLine != nListLine)
	{
		long hwnd = g_dm->FindWindow(L"MapleStoryClass", L"MapleStory");
		if (hwnd != 0) {
		
			KillProcess(L"MapleStory.exe");
			//ScriptDelay(index, 1000);
			g_dm->delay(1000);
		}
		if (ChangeLine(arrLineCode[nListLine])) {
			g_IniFile.SetInt(L"Set", L"CodeLine", nListLine);
			g_main_cwnd->SetDlgItemTextW(IDC_EDIT3, NumberToString(nListLine));
		}
	}
}

void SetTaskState(long index, const TCHAR * state)
{
	_tcscpy(g_info[index].task_state, state);
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);
}

// 脚本主线程,脚本的主要逻辑在这里处理
unsigned WINAPI MainThread(PVOID pParam)
{
	long index = (long)(DWORD_PTR)pParam;
	g_dmIndex = index;
	CDm * dm;
	// 初始化当前线程com组件为MTA模式
	CoInitializeEx(NULL, 0);
	g_info[index].thread_state = State_Runing;
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);
	// 创建对象
	g_info[index].dm = new CDm;
	
	dm = g_info[index].dm;

	// 检测对象是否创建成功,虽然这个一般不会失败,但为了程序健壮性考虑还是加上,如果内存吃紧，还是可能会失败
	if (dm == NULL || dm->Ver().GetLength() == 0)
	{
		Log(_T("对象创建失败"));
		ThreadNotifyUI_Post(NOTIFY_STOP, index);
		return 0;
	}
	// 开启全局共享字库
	dm->EnableShareDict(1);

	// 其他设置,比如路径等等 当前目录
	long ret = dm->SetPath(_T("c:\\MobileGame\\pic\\"));
	//g_main_cwnd->AppendText(L"绑定图片" + NumberToString(ret));
	dm->SetDict(0, L"jinbi.txt");
	dm->SetDict(1, L"code.txt");
	
	dm->SetShowErrorMsg(0);
	// 开始绑定,主绑定一定要第一个绑定,并且主绑定所在的线程绝对不能结束,否则会造成绑定失效
	//long dm_ret = dm->BindWindowEx(g_info[index].hwnd, _T("normal"), _T("normal"), _T("normal"), _T("dx.public.anti.api"), 0);
	//if (dm_ret != 1)
	//{
	//	Log(_T("主:绑定失败，错误码:%d"), dm->GetLastError());
	//	// 通知主线程进行结束操作(释放资源)
	//	ThreadNotifyUI_Post(NOTIFY_STOP, index);
	//	return 0;
	//}
	// 禁止输入
	//dm->LockInput(4);
	// 我们可以创建副线程了
	// 更新副线程信息
	g_info[index + MAX_HWND].thread_state = State_Starting;
	// 通知UI,副线程开始创建了
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index + MAX_HWND);
	// 创建副线程
	//调式测试
	g_info[index + MAX_HWND].handle = (HANDLE)_beginthreadex(0, 0, SubThread, (PVOID)(DWORD_PTR)(index + MAX_HWND), 0, 0);
	if (g_info[index + MAX_HWND].handle == NULL)
	{
		// 这里必须要解绑,因为模式0和2不在当前线程解绑的话,会导致无法解绑
		dm->UnBindWindow();

		Log(_T("创建副线程失败"));
		// 通知主线程进行结束操作(释放资源)
		ThreadNotifyUI_Post(NOTIFY_STOP, index);
		return 0;
	}
	int count = g_main_cwnd->m_list_info.GetItemCount();
	//刷扎昆
	CScriptMaple* pScript=new CScriptMaple(index,dm);
	//指定子线程脚本类
	g_info[index].pScript = pScript;
	g_info[index + MAX_HWND].pScript = pScript;
	//if (g_main_cwnd->m_ZhaKun.GetCheck() == 1) {
	//	pScript = new CScriptMapleZk;

	//}
	//else {//刷乌鲁斯
	//	pScript = new CScriptMapleWls;

	//}
	for (int i = 0; i < count; i++)
	{
		CString strState = g_main_cwnd->m_list_info.GetItemText(i, 6);
		if (strState != L"账号错误" &&
			strState != L"二密错误" &&
			strState != L"账号在线" &&
			strState != L"完成" &&
			strState != L"武器未装备")
		{
			int nListCodeLine = _wtoi(g_main_cwnd->m_list_info.GetItemText(i, 12));
			if (nListCodeLine == 0) {
				nListCodeLine = _wtoi(g_main_cwnd->m_list_info.GetItemText(i, 11));
			}
			int nCodeLine = g_IniFile.GetInt(L"Set", L"CodeLine");
			SwitchingLines(nCodeLine, nListCodeLine);
			pScript->SetIndex(i, true);
			if (g_main_cwnd->m_ZhaKun.GetCheck() == 1 ) {
				CScriptMapleZk* pScriptZk = (CScriptMapleZk*)pScript;
				pScriptZk->DoWork();
			}
			else {
				CScriptMapleWls* pScriptWls = (CScriptMapleWls*)pScript;
				if (g_main_cwnd->m_wlsYou.GetCheck() == 1) {//刷乌鲁斯邮票
					pScriptWls->DoWorkYou();
				}
				else {
					pScriptWls->DoWork();
				}
			}

			strState = g_main_cwnd->m_list_info.GetItemText(i, 6);//查询当期状态是否完成
			if (strState == L"未完成") {
				i = i - 1;
			}

		}
	}

	if (g_main_cwnd->m_ZhaKun.GetCheck() == 1) {
		CloseWindows();
	}
	return 0;
}

// 脚本副线程,用于检测异常等
unsigned WINAPI SubThread(PVOID pParam)
{
	long index = (long)(DWORD_PTR)pParam;

	CDm * dm;

	// 初始化当前线程com组件为MTA模式
	CoInitializeEx(NULL, 0);

	g_info[index].thread_state = State_Runing;
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

	// 创建对象
	g_info[index].dm = new CDm;
	dm = g_info[index].dm;

	// 检测对象是否创建成功,虽然这个一般不会失败,但为了程序健壮性考虑还是加上,如果内存吃紧，还是可能会失败
	if (dm == NULL || dm->Ver().GetLength() == 0)
	{
		Log(_T("对象创建失败"));
		//SetExcepState(index, _T("对象创建失败"));
		return 0;
	}

	// 开启全局共享字库
	dm->EnableShareDict(1);
	dm->SetShowErrorMsg(0);
	// 其他设置,比如路径等等
	//dm->SetPath(_T("c:\test_game"));
	long ret = dm->SetPath(_T("c:\\MobileGame\\pic\\"));

	//g_info[index].dm->BindWindowEx(g_info[index].hwnd, L"normal", L"normal", L"normal", L"", 0);
	//long dm_ret = dm->BindWindowEx(g_info[index].hwnd, _T("normal"), _T("normal"), _T("dx"), _T("dx.public.anti.api"), 0);
	//if (dm_ret != 1)
	//{
	//	//Log(_T("副:绑定失败，错误码:%d"), dm->GetLastError());
	//	// 通知主线程进行结束操作(释放资源)
	//	//SetExcepState(index, _T("副:绑定失败"));
	//	return 0;
	//}
	g_info[index].pScript->SetSubDm(dm);

	int nCount = 0;
	while (1)
	{
		// 检测一些异常,比如突然弹出的对话框，目标窗口被关闭或者掉线等突发情况
		// 比如检测到掉线，可考虑通知UI,然后重新运行
		CheckException(index);
		//ScriptDelay(index, 3000);
		nCount++;
		if (nCount % 10 == 0) {
			Sleep(1000);
			g_main_cwnd->AppendText(L"当前状态：" + NumberToString(g_info[index].pScript->GetState()));
		}
	}
	return 0;
}

void CheckException(long index)
{
	
	if (g_main_cwnd->m_ZhaKun.GetCheck() == 1) {
		CScriptMapleZk* pScriptZk =(CScriptMapleZk*) g_info[index].pScript;
		pScriptZk->CheckException();
		pScriptZk->CheckGameState();
		
	}
	else {
		CScriptMapleWls* pScriptWls = (CScriptMapleWls*)g_info[index].pScript;
		//pScriptWls->CheckException();
		pScriptWls->CheckGameState();
		Sleep(100);
	}
	
	//任务开始时检查窗口是否存在

}


//
////void DoWorkWlsYou(long index, int taskIndex, bool bLoginState) {
////	if (LoginClientWls(index, taskIndex)) {
////		if (LoginGameWls(index, taskIndex)) {
////			 WlsYouPiao(index, taskIndex);
////		}
////	}
////}
//
//void SetExcepState(long index, const TCHAR * state)
//{
//	_tcscpy(g_info[index].excep_state, state);
//	ThreadNotifyUI_Post(NOTIFY_STOP, index);
//}
//
//// 脚本副线程,用于检测异常等
////unsigned WINAPI SubThread(PVOID pParam)
////{
////	long index = (long)(DWORD_PTR)pParam;
////
////	CDm * dm;
////
////	// 初始化当前线程com组件为MTA模式
////	CoInitializeEx(NULL, 0);
////
////	g_info[index].thread_state = State_Runing;
////	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);
////
////	// 创建对象
////	g_info[index].dm = new CDm;
////	dm = g_info[index].dm;
////
////	// 检测对象是否创建成功,虽然这个一般不会失败,但为了程序健壮性考虑还是加上,如果内存吃紧，还是可能会失败
////	if (dm == NULL || dm->Ver().GetLength() == 0)
////	{
////		Log(_T("对象创建失败"));
////		SetExcepState(index, _T("对象创建失败"));
////		return 0;
////	}
////
////	// 开启全局共享字库
////	dm->EnableShareDict(1);
////	dm->SetShowErrorMsg(0);
////	// 其他设置,比如路径等等
////	//dm->SetPath(_T("c:\test_game"));
////	long ret = dm->SetPath(_T("c:\\MobileGame\\pic\\"));
////
////	//g_info[index].dm->BindWindowEx(g_info[index].hwnd, L"normal", L"normal", L"normal", L"", 0);
////	//long dm_ret = dm->BindWindowEx(g_info[index].hwnd, _T("normal"), _T("normal"), _T("dx"), _T("dx.public.anti.api"), 0);
////	//if (dm_ret != 1)
////	//{
////	//	Log(_T("副:绑定失败，错误码:%d"), dm->GetLastError());
////	//	// 通知主线程进行结束操作(释放资源)
////	//	SetExcepState(index, _T("副:绑定失败"));
////	//	return 0;
////	//}
////
////
////	while (1)
////	{
////		// 检测一些异常,比如突然弹出的对话框，目标窗口被关闭或者掉线等突发情况
////		// 比如检测到掉线，可考虑通知UI,然后重新运行
////		CheckException(index);
////		//ScriptDelay(index, 3000);
////	}
////}
//
//void CheckException(long index)
//{
//	CDm * dm = g_info[index].dm;
//	
//	ScriptDelay(index, 1000);
//
//
//
//}
//
//
void CloseWindows() {

	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		
		g_main_cwnd->MessageBox(_T("关机失败..."), _T("警告"), MB_OK);
		return;
	}
	LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
		&tkp.Privileges[0].Luid);
	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL);
	if (GetLastError() != ERROR_SUCCESS)
	{
		g_main_cwnd->MessageBox(_T("关机失败..."), _T("警告"), MB_OK);
		return;
	}
	ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0);

}
